home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / unix / mp14tar.z / mp14tar / mpack / macos.c < prev    next >
C/C++ Source or Header  |  1994-06-01  |  11KB  |  438 lines

  1. /* macos.c -- operating system dependant mpack code for the Macintosh
  2.  *
  3.  * (C) Copyright 1993-1994 by Christopher J. Newman
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of Christopher J. Newman not be used in
  11.  * advertising or publicity pertaining to distribution of the software without
  12.  * specific, written prior permission.  Christopher J. Newman makes no
  13.  * representations about the suitability of this software for any purpose.  It
  14.  * is provided "as is" without express or implied warranty.
  15.  *
  16.  * CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  17.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
  18.  * SHALL CHRISTOPHER J. NEWMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  19.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  20.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  21.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  22.  * OF THIS SOFTWARE.
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <ctype.h>
  27. #include <string.h>
  28. #include <errno.h>
  29. #include "common.h"
  30. #include "macnapp.h"
  31. #include "macmpack.h"
  32.  
  33. extern char *malloc(), *realloc();
  34.  
  35. char copy_buf[COPY_BUFSIZE];
  36.  
  37. char *xmalloc(unsigned size)
  38. {
  39.     char *ret;
  40.  
  41.     if (ret = malloc((unsigned) size))
  42.       return ret;
  43.  
  44.     yell("Virtual memory exhausted");
  45.     exit(1);
  46. }
  47.  
  48. char *xrealloc (char *ptr, unsigned size)
  49. {
  50.     char *ret;
  51.  
  52.     /* xrealloc (NULL, size) behaves like xmalloc (size), as in ANSI C */
  53.     if (ret = !ptr ? malloc ((unsigned) size) : realloc (ptr, (unsigned) size))
  54.       return ret;
  55.  
  56.     yell("Virtual memory exhausted");
  57.     exit(1);
  58. }
  59.  
  60. char *strsave(char *str)
  61. {
  62.     char *p = xmalloc(strlen(str)+1);
  63.     strcpy(p, str);
  64.     return p;
  65. }
  66.  
  67. /* save output filename buffer */
  68. static char *output_fname = NULL;
  69. static short applefile_flag = 0;
  70. static FSSpec fspec;
  71.  
  72. /* TMPL resource for IDna -- ID to name mappings
  73.  */
  74. char TMPL[] = {
  75.     16 , 'D', 'i', 'r', 'e', 'c', 't', 'o',
  76.     'r', 'y', ' ', 'N', 'u', 'm', 'b', 'e',
  77.     'r', 'D', 'W', 'R', 'D'
  78. };
  79.  
  80. /* rename or copy a file to a new location
  81.  */
  82. void rename_or_copy(srcfname, dstfname, dstvRefNum)
  83.     char *srcfname;
  84.     PCstr *dstfname;
  85.     short dstvRefNum;
  86. {
  87.     PCstr tstr[257];
  88.     short dstvol, srefnum, drefnum;
  89.     long dirid, procid = 0, count;
  90.     WDPBRec wdpb;
  91.     HParamBlockRec hpb;
  92.     CMovePBRec cpb;
  93.     
  94.     wdpb.ioNamePtr = P(tstr);
  95.     if (PBHGetVol(&wdpb, FALSE) != noErr) return;
  96.     if (GetWDInfo(dstvRefNum, &dstvol, &dirid, &procid) != noErr) return;
  97.     CtoPCstrcpy(tstr, srcfname);
  98.     if (HOpen(0, 0, P(tstr), fsRdPerm, &srefnum) != noErr) return;
  99.     if (GetEOF(srefnum, &count) == noErr && !count) {
  100.         FSClose(srefnum);
  101.         return;
  102.     }
  103.     if (wdpb.ioWDVRefNum == dstvol) {
  104.         /* files on same drive -- do a rename/move */
  105.         FSClose(srefnum);
  106.         hpb.fileParam.ioNamePtr = P(tstr);
  107.         hpb.fileParam.ioVRefNum = 0;
  108.         hpb.ioParam.ioMisc = (Ptr) P(dstfname);
  109.         hpb.fileParam.ioDirID = 0;
  110.         if (PBHRenameSync(&hpb) == noErr && wdpb.ioWDDirID != dirid) {
  111.             cpb.ioNamePtr = P(dstfname);
  112.             cpb.ioVRefNum = 0;
  113.             cpb.ioNewName = NULL;
  114.             cpb.ioNewDirID = dirid;
  115.             cpb.ioDirID = 0;
  116.             PBCatMoveSync(&cpb);
  117.         }
  118.     } else {
  119.         /* files on different drive -- do a copy */
  120.         if (Create(P(dstfname), dstvRefNum, _fcreator, _ftype) != noErr) {
  121.             FSClose(srefnum);
  122.             return;
  123.         }
  124.         if (HOpen(dstvRefNum, 0, P(dstfname), fsWrPerm, &drefnum) != noErr) {
  125.             FSClose(srefnum);
  126.             FSDelete(P(dstfname), dstvRefNum);
  127.             return;
  128.         }
  129.         count = sizeof (copy_buf);
  130.         while (FSRead(srefnum, &count, (Ptr) copy_buf) != noErr && count > 0) {
  131.             FSWrite(drefnum, &count, (Ptr) copy_buf);
  132.             count = sizeof (copy_buf);
  133.         }
  134.         FSClose(srefnum);
  135.         FSClose(drefnum);
  136.     }
  137. }
  138.  
  139. /* Generate a message-id */
  140. char *os_genid()
  141. {
  142.     char *result;
  143.     long tick;
  144.     unsigned long time;
  145.  
  146.     tick = TickCount();
  147.     result = malloc(64);
  148.     GetDateTime(&time);
  149.     HLock((Handle) mpack_prefs);
  150.     sprintf(result, "%lu.%lu@%s", tick, time, (*mpack_prefs)->internet_host);
  151.     HUnlock((Handle) mpack_prefs);
  152.     
  153.     /* make sure tick count is bumped before we return... */
  154.     while (tick == TickCount());
  155.     
  156.     return (result);
  157. }
  158.  
  159. /* Create and return directory for a message-id
  160.  */
  161. char *os_idtodir(id)
  162. char *id;
  163. {
  164.     static PCstr buf[257];
  165.     static unsigned char mpackdir[] = "\pmpack-tmp";
  166.     PCstr idbuf[257];
  167.     char *fname;
  168.     short wrefnum, vrefnum, resfile, uqid, createflag = 0;
  169.     long dirid, procid;
  170.     OSErr err;
  171.     Handle h;
  172.     ResType type = 'IDna';
  173.     FInfo finfo;
  174.  
  175.     /* get name of default volume */
  176.     if (GetVol(P(buf), &wrefnum) != noErr) return (NULL);
  177.     procid = 0;
  178.     if (GetWDInfo(wrefnum, &vrefnum, &dirid, &procid) != noErr) return (NULL);
  179.     
  180.     /* try creating tmp dir */
  181.     err = DirCreate(vrefnum, 0, mpackdir, &dirid);
  182.     if (err != noErr && err != dupFNErr) return (NULL);
  183.     CtoPCstrcat(buf, ":");
  184.     PtoPCstrcat(buf, (char *) mpackdir);
  185.     CtoPCstrcat(buf, ":");
  186.     fname = C(buf) + PCstrlen(buf);
  187.     
  188.     /* open the map file */
  189.     strcpy(fname, "map");
  190.     SetPlen(buf);
  191.     CreateResFile(P(buf));
  192.     if ((err = ResError()) == noErr && GetFInfo(P(buf), vrefnum, &finfo) == noErr) {
  193.         finfo.fdType = 'rsrc';
  194.         finfo.fdCreator = 'RSED';
  195.         SetFInfo(P(buf), vrefnum, &finfo);
  196.     }
  197.     if ((resfile = OpenResFile(P(buf))) < 0) return (NULL);
  198.     if (err == noErr && PtrToHand((Ptr) TMPL, &h, sizeof (TMPL)) == noErr) {
  199.         AddResource(h, 'TMPL', 1000, "\pIDna");
  200.     }
  201.     
  202.     /* is there a mapping for the id? */
  203.     CtoPCstrcpy(idbuf, id);
  204.     h = GetNamedResource(type, P(idbuf));
  205.     
  206.     /* no mapping -- create one */
  207.     if (!h) {
  208.         createflag = 1;
  209.         while ((uqid = UniqueID(type)) < 128);
  210.         h = NewHandle(sizeof (short));
  211.         if (h) (**(short **)h) = uqid;
  212.         AddResource(h, type, uqid, P(idbuf));
  213.         if ((err = ResError()) != noErr) {
  214.             CloseResFile(resfile);
  215.             return (NULL);
  216.         }
  217.     } else {
  218.         uqid = ** (short **) h;
  219.     }
  220.     
  221.     /* set directory name & create it */
  222.     sprintf(fname, "%d:", uqid);
  223.     SetPlen(buf);
  224.     err = DirCreate(vrefnum, 0, P(buf), &dirid);
  225.     if (err != noErr && err != dupFNErr) {
  226.         RmveResource(h);
  227.         DisposHandle(h);
  228.         h = NULL;
  229.     }
  230.  
  231.     /* done with map file */
  232.     CloseResFile(resfile);
  233.     
  234.     return (h ? C(buf) : NULL);
  235. }
  236.  
  237. /*
  238.  * We are done with the directory returned by os_idtodir()
  239.  * Remove it
  240.  */
  241. os_donewithdir(dir)
  242. char *dir;
  243. {
  244.     PCstr buf[257];
  245.     short uqid, resfile;
  246.     char *fname;
  247.     Handle h;
  248.     
  249.     CtoPCstrcpy(buf, dir);
  250.     HDelete(0, 0, P(buf));
  251.     fname = strchr(C(buf), ':');
  252.     if (fname && (fname = strchr(fname + 1, ':'))) {
  253.         uqid = atoi(fname + 1);
  254.         strcpy(fname, ":map");
  255.         SetPlen(buf);
  256.         if ((resfile = OpenResFile(P(buf))) >= 0) {
  257.             h = GetResource('IDna', uqid);
  258.             if (h) {
  259.                 RmveResource(h);
  260.                 DisposHandle(h);
  261.             }
  262.             CloseResFile(resfile);
  263.         }
  264.     }
  265. }
  266.  
  267. /* Set the file types based on a content type
  268.  */
  269. void setTypeCreator(char *contenttype)
  270. {
  271.     PCstr tstr[257];
  272.     Handle h;
  273.     
  274.     CtoPCstrncpy(tstr, contenttype, 255);
  275.     h = GetNamedResource('TyCr', P(tstr));
  276.     if (h) {
  277.         _ftype = (*(OSType **)h)[0];
  278.         _fcreator = (*(OSType **)h)[1];
  279.     } else {
  280.         _ftype = '????';
  281.         _fcreator = 'mPAK';
  282.     }
  283. }
  284.  
  285. /* rename the description file
  286.  */
  287. void renameDescFile(char *fname, short vRefNum)
  288. {
  289.     PCstr tstr[65];
  290.     char *p;
  291.  
  292.     setTypeCreator("text/plain");
  293.  
  294.     /* save description file */
  295.     CtoPCstrcpy(tstr, fname);
  296.     if (p = strrchr(C(tstr), '.')) *p = '\0';
  297.     strcat(C(tstr), ".desc");
  298.     SetPlen(tstr);
  299.     rename_or_copy(TEMPFILENAME, tstr, vRefNum);
  300.     (void) remove(TEMPFILENAME);
  301. }
  302.  
  303. /*
  304.  * Create a new file, with suggested filename "fname".
  305.  * "fname" may have come from an insecure source, so clean it up first.
  306.  * It may also be null.
  307.  * "contentType" is passed in for use by systems that have typed filesystems.
  308.  * "flags" contains a bit pattern describing attributes of the new file.
  309.  */
  310. FILE *os_newtypedfile(fname, contentType, flags)
  311. char *fname;
  312. char *contentType;
  313. int flags;
  314. {
  315.     char *p;
  316.     int applefile;
  317.     FILE *outfile = 0, *tmpf;
  318.     extern Cursor watch;
  319.     Point where;
  320.     SFReply reply;
  321.     PCstr tstr[257];
  322.  
  323.     if (!fname) fname = "";
  324.     
  325.     /* Translate ':' to underscore */
  326.     for (p=fname; *p; p++) {
  327.         if (*p == ':' || !isprint(*p)) *p = '_';
  328.     }
  329.     
  330.     /* chop filename to length */
  331.     if (strlen(fname) > 31) {
  332.         fname += strlen(fname) - 31;
  333.     }
  334.  
  335.     /* get filename from user */
  336.     sprintf(C(tstr), "Saving file: %s\rType: %s", fname[0] ? fname : "Untitled", contentType);
  337.     chat(C(tstr));
  338.     applefile = !strcmp(contentType, "application/applefile");
  339.     if (!applefile && (!applefile_flag || !(flags & FILE_INAPPLEDOUBLE))) {
  340.         SetCursor(&arrow);
  341.         where.h = where.v = 0;
  342.         CtoPstr(fname);
  343.         SFPutFile(where, "\pSave decoded file as:",
  344.             fname[0] ? (unsigned char *) fname : "\pUntitled", NULL, &reply);
  345.         PtoCstr((unsigned char *) fname);
  346.         SetCursor(&watch);
  347.         if (!reply.good) return (NULL);
  348.     }
  349.  
  350.     /* set the type */
  351.     setTypeCreator(contentType);
  352.  
  353.     /* save file */
  354.     tmpf = tmpfile();
  355.     if (applefile) {
  356.         outfile = tmpf;
  357.         tmpf = NULL;
  358.     } else if ((flags & FILE_INAPPLEDOUBLE) && applefile_flag) {
  359.         outfile = Macopen(tmpf, fspec.name, fspec.vRefNum, fspec.parID,
  360.             flags & FILE_BINARY, 0, fsWrPerm);
  361.     } else {
  362.         Create(reply.fName, reply.vRefNum, _fcreator, _ftype);
  363.         outfile = Macopen(tmpf, reply.fName, reply.vRefNum, 0,
  364.             flags & FILE_BINARY, 0, fsWrPerm);
  365.     }
  366.     applefile_flag = applefile;
  367.     if (tmpf) fclose(tmpf);
  368.     PtoCstr(reply.fName);
  369.     fname = (char *) reply.fName;
  370.     if (!outfile) {
  371.         sprintf(C(tstr), "Couldn't open file %s", fname);
  372.         warn(C(tstr));
  373.         return (0);
  374.     }
  375.     
  376.     if (output_fname) free(output_fname);
  377.     output_fname = strsave(fname);
  378.     
  379.     renameDescFile(fname, reply.vRefNum);
  380.  
  381.     return outfile;
  382. }
  383.  
  384. /*
  385.  * Close a file opened by os_newTypedFile()
  386.  */
  387. os_closetypedfile(outfile)
  388. FILE *outfile;
  389. {
  390.     char buf[128];
  391.     
  392.     if (applefile_flag) {
  393.         rewind(outfile);
  394.         if (decode_applefile(outfile, &fspec) < 0) {
  395.             sprintf(buf, "Failed to decode file %s", output_fname);
  396.             warn(buf);
  397.             applefile_flag = 0;
  398.         }
  399.     }
  400.  
  401.     /* close file */
  402.     fclose(outfile);
  403. }
  404.  
  405. /*
  406.  * Warn user that the MD5 digest of the last file created by os_newtypedfile()
  407.  * did not match that supplied in the Content-MD5: header.
  408.  */
  409. os_warnMD5mismatch()
  410. {
  411.     char *warning;
  412.  
  413.     warning = xmalloc(strlen(output_fname) + 100);
  414.     sprintf(warning, "%s was corrupted in transit",
  415.         output_fname);
  416.     warn(warning);
  417.     free(warning);
  418. }
  419.  
  420. /* bring up an error dialog for a file error
  421.  */
  422. void os_perror(char *str)
  423. {
  424.     extern int errno;
  425.     char *err = strerror(errno), *scan;
  426.     char msg[256];
  427.     short maxflen;
  428.     
  429.     maxflen = 255 - (strlen(err) + 2);
  430.     if (strlen(str) > maxflen) {
  431.         str += strlen(str) - maxflen;
  432.         for (scan = str; *scan && *scan++ != ':';);
  433.         if (*scan) str = scan;
  434.     }
  435.     sprintf(msg, "%s: %s", str, err);
  436.     yell(msg);
  437. }
  438.